package cn.tedu.suppermemory.service.impl;

import cn.tedu.suppermemory.ex.ServiceException;
import cn.tedu.suppermemory.mapper.UserMapper;
import cn.tedu.suppermemory.pojo.dto.UserAddNewDTO;
import cn.tedu.suppermemory.pojo.dto.UserLoginDTO;
import cn.tedu.suppermemory.pojo.entity.User;
import cn.tedu.suppermemory.pojo.vo.UserListItemVO;
import cn.tedu.suppermemory.pojo.vo.UserStandardVO;
import cn.tedu.suppermemory.security.UserDetails;
import cn.tedu.suppermemory.service.IUserService;
import cn.tedu.suppermemory.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private long durationInMinute;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public String login(UserLoginDTO userLoginDTO) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", userLoginDTO);
        // 执行认证
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                userLoginDTO.getUsername(), userLoginDTO.getPassword());
        Authentication authenticationResult
                = authenticationManager.authenticate(authentication);
        log.debug("认证通过，认证结果：{}", authenticationResult);
        log.debug("认证通过，认证结果中的当事人：{}", authenticationResult.getPrincipal());

        // 将通过认证的管理员的相关信息存入到JWT中
        // 准备生成JWT的相关数据
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        UserDetails principal = (UserDetails) authenticationResult.getPrincipal();
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", principal.getId());
        claims.put("username", principal.getUsername());
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        // 生成JWT
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Signature
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 完成
                .compact();
        // 返回JWT
        log.debug("返回JWT数据，JWT：{}", jwt);
        return jwt;
    }

    @Override
    public void addNew(UserAddNewDTO userAddNewDTO) {
        log.info("开始处理【用户注册】业务，参数：{}",userAddNewDTO);

        // 检查角色ID的数组中是否包含1号角色
        Long[] roleIds = userAddNewDTO.getRoleIds();
        for (int i = 0; i < roleIds.length; i++) {
            if (roleIds[i] == 1) {
                String message = "添加管理员失败，非法访问！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        {
            // 从参数对象中取出用户名
            String username = userAddNewDTO.getUsername();
            // 调用adminMapper.countByUsername()执行统计
            int count = userMapper.countByUsername(username);
            // 判断统计结果是否大于0
            if (count > 0) {
                // 是：抛出异常（ERR_CONFLICT）
                String message = "添加管理员失败，尝试使用的用户名已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        {
            // 从参数对象中取出手机号码
            String phone = userAddNewDTO.getPhone();
            // 调用adminMapper.countByPhone()执行统计
            int count = userMapper.countByPhone(phone);
            // 判断统计结果是否大于0
            if (count > 0) {
                // 是：抛出异常（ERR_CONFLICT）
                String message = "添加管理员失败，尝试使用的手机号码已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        {
            // 从参数对象中取出电子邮箱
            String email = userAddNewDTO.getEmail();
            // 调用adminMapper.countByEmail()执行统计
            int count = userMapper.countByEmail(email);
            // 判断统计结果是否大于0
            if (count > 0) {
                // 是：抛出异常（ERR_CONFLICT）
                String message = "添加管理员失败，尝试使用的电子邮箱已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        User user = new User();
        BeanUtils.copyProperties(userAddNewDTO,user);
        log.info("正在处理【用户注册】业务，参数：{}",user);
        // 设置初始登录次数
        user.setLoginCount(0);
        // 处理密码加密
        String rawPassword = user.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        user.setPassword(encodedPassword);
        userMapper.insert(user);
    }

    @Override
    public void delete(Long id) {

        // 不允许删除1号管理员
        if (id == 1) {
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查尝试删除的数据是否存在
        Object queryResult = userMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 执行删除--管理员表
        log.debug("即将执行删除数据，参数：{}", id);
        int rows = userMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }

    @Override
    public UserStandardVO getStandardById(Long id) {
        UserStandardVO standardById = userMapper.getStandardById(id);
        return standardById;
    }

    @Override
    public List<UserListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务，参数：无");
        List<UserListItemVO> list = userMapper.list();

        Iterator<UserListItemVO> iterator = list.iterator();
        while (iterator.hasNext()) {
            UserListItemVO admin = iterator.next();
            if (admin.getId() == 1) {
                iterator.remove();
                break;
            }
        }

        return list;
    }

    private void updateEnableById(Long id, Integer enable) {
        String[] enableText = {"禁用", "启用"};
        log.debug("开始处理【{}管理员】的业务，ID：{}，目标状态：{}", enableText[enable], id, enable);
        // 不允许调整1号管理员的启用状态
        if (id == 1) {
            String message = enableText[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查数据是否存在
        UserStandardVO queryResult = userMapper.getStandardById(id);
        if (queryResult == null) {
            String message = enableText[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查当前状态是否与参数表示的状态相同
        if (queryResult.getEnable().equals(enable)) {
            String message = enableText[enable] + "管理员失败，当前管理员已经处于"
                    + enableText[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 准备执行更新
        User admin = new User();
        admin.setId(id);
        admin.setEnable(enable);
        log.debug("即将修改数据，参数：{}", admin);
        int rows = userMapper.update(admin);
        if (rows != 1) {
            String message = enableText[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }
}
